from simpy import Environment, Resource

from x_pc.core import System
from x_pc.core.transport import Transport
from x_pc.core.unit.unit_202_zbcr import ZBCRSystem
from x_pc.core.unit.unit_210_iqccr import IQCCRSystem
from x_pc.helpers import hc_work_num
from x_pc.model.model import check_fix_task, TaskCtx


class HC(Transport, System):
    """
    401 环穿
    环穿(HC)
    """
    system_zb = None
    # 环穿列表(缓存)
    hc_list: list[Resource] = []

    sys_data = None

    def __init__(self, env: Environment, name: str, system_zb, kwargs, sys_data):
        self.system_zb = system_zb
        self.sys_data = sys_data
        Transport.__init__(self, env, name, kwargs)
        System.__init__(self, env, name)
        self.__init_hc_list()
        self.sys_data.logger.info(f'[PC] {self.name} 初始化完成，环穿可用数量: {len(self.hc_list)}')

    def __init_hc_list(self):
        self.hc_list = [Resource(self.env) for _ in range(self.cache_nums())]

    def run_task(self, task_ctx: TaskCtx):
        if not self.hc_list:
            while self.running:
                yield self.env.timeout(1)
                if self.hc_list:
                    break
        # 若存在可用 环穿资源 则直接执行任务
        self.env.process(self.do_run_task(task_ctx))

    def do_run_task(self, task_ctx: TaskCtx):
        # 设备是否锁定判断
        task = task_ctx.task
        process = task.process
        time_cost = self.cost() / self.sys_data.time_cost_ratio
        pending_list = self.sys_data.get_pending_device(self.device_type(), self.device_code())
        if not hc_work_num(self.env.now, time_cost, pending_list) < self.cache_nums():
            while self.running:
                yield self.env.timeout(1)
                if hc_work_num(self.env.now, time_cost, pending_list) < self.cache_nums():
                    break
        #
        hc = self.hc_list.pop(0)
        with hc.request() as req:
            yield req
            #
            process.begin_pos = task.pre_process().device_code
            process.begin_ts = self.env.now
            process.set_origin_pack_type(task.pre_process().target_pack_type)
            process.set_origin_sku_num(task.pre_process().target_sku_num)
            process.operate_pack_type = process.ext_work_type.operate_pack_type
            process.operate_pack_num = 1
            # 将任务占用的缓存 从栈板出入口移除
            yield task_ctx.zbsx.store.get()
            #
            process.device_type = self.device_type()
            process.device_code = self.device_code()
            yield self.env.timeout(time_cost)
            #
            process.end_pos = process.device_code
            process.end_ts = self.env.now
        self.hc_list.append(hc)

        # TODO: 将任务放置到了  栈板出入口(202 zbcr)
        # 优先使用zbcr(202)，当没有设备可用时，使用210
        if self.system_zb.zbcr.zbcr_list:
            zbcr: ZBCRSystem = self.system_zb.zbcr
            # 将任务丢至 栈板出入系统
            zbcr.push_task(TaskCtx(task_ctx.task))
        else:
            iqccr: IQCCRSystem = self.system_zb.iqccr
            # 将任务丢至 出入货口设备组
            iqccr.push_task(TaskCtx(task_ctx.task))
        # 修正数据
        check_fix_task(task_ctx.task)

    @staticmethod
    def device_type() -> int:
        return 401
